package org.budo.dubbo.protocol.http.view.render.impl;

import java.io.IOException;

import org.budo.dubbo.protocol.http.exception.BudoRuntimeException;
import org.budo.dubbo.protocol.http.invocation.adapter.ProtocolRequest;
import org.budo.dubbo.protocol.http.invocation.adapter.ProtocolResponse;
import org.budo.dubbo.protocol.http.view.render.AbstractViewRender;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.rpc.RpcResult;

/**
 * @author lmw
 */
public class WebHttpJsonViewRender extends AbstractViewRender {
    private static final String CONTENT_TYPE = "Content-Type";

    private static final String APPLICATION_JSON_CHARSET_UTF_8 = "application/json; charset=UTF-8";

    private static final Logger log = LoggerFactory.getLogger(WebHttpJsonViewRender.class);

    @Override
    protected void addHeader(ProtocolResponse response, Object result) {
        response.addHeader(CONTENT_TYPE, APPLICATION_JSON_CHARSET_UTF_8);
    }

    @Override
    protected void writeResponse(ProtocolRequest protocolRequest, ProtocolResponse response, Object result) throws IOException {
        if (null == result) {
            String message = "#27 result-is-null, request=" + protocolRequest + ", protocolRequest=" + protocolRequest;
            BudoRuntimeException exception = new BudoRuntimeException(message);
            this.renderException(protocolRequest, response, exception);
            return;
        }

        if (result instanceof Throwable) {
            this.renderException(protocolRequest, response, (Throwable) result);
            return;
        }

        if (result instanceof RpcResult) {
            this.renderRpcResult(protocolRequest, response, (RpcResult) result);
            return;
        }

        String message = "#43 result-type-unknown, result=" + result + ", type=" + result.getClass() + ", protocolRequest=" + protocolRequest;
        BudoRuntimeException exception = new BudoRuntimeException(message);
        this.renderException(protocolRequest, response, exception);
    }

    protected void renderRpcResult(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, RpcResult result) throws IOException {
        if (result.hasException()) {
            Throwable exception = result.getException();
            this.renderException(protocolRequest, protocolResponse, exception);
            return;
        }

        Object resultValue = result.getValue();
        this.renderResultValue(protocolRequest, protocolResponse, resultValue);
    }

    protected void renderResultValue(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, Object rpcResultValue) throws IOException {
        Object parsedResult = CollectionUtils.toMap("result", rpcResultValue);
        super.processResultValueAndSerializeAndWriteToResponse(protocolRequest, protocolResponse, parsedResult);
    }

    protected void renderException(ProtocolRequest protocolRequest, ProtocolResponse protocolResponse, Throwable exception) throws IOException {
        log.error("#71 renderException, this=" + this + ", protocolRequest=" + protocolRequest + ", protocolResponse=" + protocolResponse + ", exception=" + exception);

        Object parsedResult = CollectionUtils.toMap("error", exception + "");
        super.processResultValueAndSerializeAndWriteToResponse(protocolRequest, protocolResponse, parsedResult);
    }
}
